package generator;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import util.Configuration;
import util.Contestant;
import util.TimeData;
import util.io.FileExporter;

/**
 * ResultsGenerator uses the data from the input files and generates the result
 * file.
 * 
 * @author team07
 */
public class ResultsGenerator {

	private Main data = new Main();

	/**
	 * Create an instance of a ResultsGenerator created from the specified
	 * TimeData object.
	 * 
	 * @param td
	 *            Specified TimeData object
	 */
	public ResultsGenerator(TimeData td) {
		this.data.td = td;
	}

	/**
	 * Generates the results and saves it to two files - each sorted differently
	 * according to the customers user stories
	 * 
	 * @param filePath_id
	 *            The path to save the first result file at
	 * @param filePath_pos
	 *            The path to save the second result file at
	 * @throws IOException
	 */
	public void generateResults(String filePath_id, String filePath_pos)
			throws IOException {
		if (Configuration.get(Configuration.COMPETITION_TYPE).equals("stage")) {
			String txt_id = this.generateResults_stage_id();
			String txt_pos = this.generateResults_stage_pos();
			FileExporter.saveToFile(filePath_id, txt_id);
			FileExporter.saveToFile(filePath_pos, txt_pos);
		} else {
			String txt_id = this.generateResults_lap_id();
			String txt_pos = this.generateResults_lap_pos();
			String html_id = HtmlTableGenerator
					.generateHtmlTableFromString(txt_id);
			String html_pos = HtmlTableGenerator
					.generateHtmlTableFromString(txt_pos);
			FileExporter.saveToFile(filePath_id, txt_id);
			FileExporter.saveToFile(filePath_pos, txt_pos);
			FileExporter.saveToFile(filePath_id.replace(".txt", ".html"),
					html_id);
			FileExporter.saveToFile(filePath_pos.replace(".txt", ".html"),
					html_pos);
		}
	}

	/**
	 * Returns a list List<TimeData> with each contestant being split into
	 * different TimeData objects according to class
	 * 
	 * @return the List<TimeData> returned
	 */
	private List<TimeData> generateResults() {

		Map<String, TimeData> map = new HashMap<String, TimeData>();

		for (Contestant c : data.td) {
			if(c.getName().equals("n/a")) c.setCategory("Icke existerande startnummer");
			String currentClass = c.getCategory();
			
			
			if (!map.containsKey(currentClass)) {
				map.put(currentClass, new TimeData());
			}
			map.get(currentClass).putContestant(c);
		}
		
		List<TimeData> list = new ArrayList<TimeData>(map.values());
		Collections.sort(list, new SortByInnerID());

		return list;

	}

	/**
	 * Returns a string with the contestant sorted by driver ID
	 * 
	 * @return The string containing the data
	 */
	private String generateResults_stage_id() {
		List<TimeData> list = this.generateResults();

		StringBuilder sb = new StringBuilder();
		for (TimeData td : list) {
			String category = td.iterator().next().getCategory();
			if (!category.equals("n/a")) {
			sb.append(category);
			sb.append("\n");
			}

			td.setNewNameIdientifier(this.data.td.getNewNameIdientifier());
			td.calculateNbrLaps();
			sb.append(td.toString_stage_id());
		}

		return sb.toString();

	}

	/**
	 * Returns a string with the contestant sorted by position
	 * 
	 * @return the string containing the data
	 */
	private String generateResults_stage_pos() {
		List<TimeData> list = this.generateResults();

		StringBuilder sb = new StringBuilder();

		for (TimeData td : list) {
			String category = td.iterator().next().getCategory();
			if (!category.equals("n/a")) {
				sb.append(category);
				sb.append("\n");
			}

			td.setNewNameIdientifier(this.data.td.getNewNameIdientifier());
			td.calculateNbrLaps();
			sb.append(td.toString_stage_pos());
		}

		return sb.toString();

	}

	/**
	 * Returns a string with the contestant sorted by driver ID
	 * 
	 * @return The string containing the data
	 */
	private String generateResults_lap_id() {
		List<TimeData> list = this.generateResults();

		StringBuilder sb = new StringBuilder();

		for (TimeData td : list) {
			String category = td.iterator().next().getCategory();
			if (!category.equals("n/a")) {
				sb.append(category);
				sb.append("\n");
			}

			td.setNewNameIdientifier(this.data.td.getNewNameIdientifier());
			td.calculateNbrLaps();
			sb.append(td.toString_lap_id());
		}

		return sb.toString();

	}

	/**
	 * Returns a string with the contestant sorted by 1) class 2) within
	 * stipulated time 3) total laps 4) total time
	 * 
	 * @return The string containing the data
	 */
	private String generateResults_lap_pos() {
		List<TimeData> list = this.generateResults();

		StringBuilder sb = new StringBuilder();

		for (TimeData td : list) {
			String category = td.iterator().next().getCategory();
			if (!category.equals("n/a")) {
				sb.append(category);
				sb.append("\n");
			}

			td.setNewNameIdientifier(this.data.td.getNewNameIdientifier());
			td.calculateNbrLaps();
			sb.append(td.toString_lap_pos());
		}

		return sb.toString();
	}
	

	/**
	 * Inner class for sorting by driver ID
	 * 
	 * @author team07
	 */
	private static class SortByInnerID implements Comparator<TimeData>, Serializable {
		
		private static final long serialVersionUID = 1L;

		public int compare(TimeData o1, TimeData o2) {
			int i1 = o1.iterator().next().getID();
			int i2 = o2.iterator().next().getID();
			return i1 - i2;
		}
	}
}
